#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>

#include "Eploller.hpp"
#include "Connection.hpp"

using namespace EplollerModule;
using connection_t = std::shared_ptr<Connection>;

class EpollServer
{
    const static int event_num = 64;

private:
public:
    EpollServer()
        : _isrunning(false)
        , _epoller(std::make_unique<Eploller>())
    {
        _epoller->Init();
    }
    
    ~EpollServer()
    {}

    void InsertConnection(connection_t &conn)
    {
        auto iter = _connections.find(conn->SockFd());
        if (iter == _connections.end())
        {
            // 1.把链接放到unordered_map进行管理
            _connections.insert(std::make_pair(conn->SockFd(), conn));
            // 2.把新插入的进来的连接，写透到内核的epoll中
            _epoller->Ctrl(conn->SockFd(), conn->GetEvents());
        }
    }

    bool IsConnectionExists(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }
    // 基于事件驱动的事件派发器
    void Dispatcher(int n)
    {
        // 对已经就绪的事件进行派发
        for (int i = 0; i < n; ++i)
        {
            // 派发给指点的模块
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            if ((revents & EPOLLERR) || (revents & EPOLLHUP))
                revents = (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLIN && IsConnectionExists(sockfd))
            {
                _connections[sockfd]->CallRecver();
            }
            if (revents & EPOLLOUT && IsConnectionExists(sockfd))
            {
                _connections[sockfd]->CallSender();
            }
        }
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller->Wait(_revs, event_num, timeout);
        Dispatcher(n);
    }

    void Loop()
    {
        _isrunning = true;
        int timeout = -1;
        while (_isrunning)
        {
            LoopOnce(timeout);
            // 超时管理
        }
    }

    void Stop()
    {
        _isrunning = false;
    }
private:
    int _port;
    std::unique_ptr<Eploller> _epoller;
    std::unordered_map<int, connection_t> _connections; // 服务器内部所有的链接
    bool _isrunning;
    struct epoll_event _revs[event_num];
};